export interface Tree {
  id: string | number;
  children: Array<Tree>;
  [key: string]: any;
}

export interface TreeChecked {
  checked: Array<string | number>;
  halfChecked: Array<string | number>;
}

enum CheckedType {
  checked,
  halfChecked,
  none,
}

interface CurrentNode {
  checked: boolean;
  id: string | number;
}

export function checked(
  tree: Tree[],
  custChecked: Array<string | number>,
  currentNode: CurrentNode,
): TreeChecked {
  const checked: Array<string | number> = [];
  const halfChecked: Array<string | number> = [];
  calculateChecked(tree, custChecked, checked, halfChecked, currentNode);
  return {
    checked,
    halfChecked,
  };
}

function getChildrenId(tree: Tree): Array<string | number> {
  const ids: Array<string | number> = [tree.id];
  if (isLeaf(tree)) {
    return ids;
  }
  for (const child of tree.children) {
    ids.push(...getChildrenId(child));
  }
  return ids;
}

function calculate(
  tree: Tree,
  custChecked: Array<string | number>,
  checked: Array<string | number>,
  halfChecked: Array<string | number>,
  currentNode: CurrentNode,
): CheckedType {
  if (isLeaf(tree)) {
    // 叶子节点必须全选
    const isChecked = custChecked.filter((item) => item === tree.id).length > 0;
    if (isChecked) {
      checked.push(tree.id);
      return CheckedType.checked;
    } else {
      return CheckedType.none;
    }
  } else {
    if (tree.id === currentNode.id && currentNode.checked) {
      checked.push(...getChildrenId(tree));
      return CheckedType.checked;
    } else if (tree.id === currentNode.id && !currentNode.checked) {
      return CheckedType.none;
    } else {
      const allCount = tree.children.length;
      let checkedCount = 0;
      let halfCheckedCount = 0;
      for (const index in tree.children) {
        const isChecked = calculate(
          tree.children[index],
          custChecked,
          checked,
          halfChecked,
          currentNode,
        );
        if (isChecked === CheckedType.checked) {
          checkedCount = checkedCount + 1;
        } else if (isChecked === CheckedType.halfChecked) {
          halfCheckedCount = halfCheckedCount + 1;
        }
      }
      if (allCount === checkedCount) {
        checked.push(tree.id);
        return CheckedType.checked;
      } else if (halfCheckedCount > 0 || (allCount > checkedCount && checkedCount > 0)) {
        halfChecked.push(tree.id);
        return CheckedType.halfChecked;
      } else {
        return CheckedType.none;
      }
    }
  }
}

/**
 * j计算树节点半选、权限id
 * @param trees 树节点
 * @param custChecked 选中的数据
 * @param checked 全选数组
 * @param halfChecked 半选数组
 * @param currentNode 当前节点的选中状态
 */
function calculateChecked(
  trees: Tree[] = [],
  custChecked: Array<string | number>,
  checked: Array<string | number>,
  halfChecked: Array<string | number>,
  currentNode: CurrentNode,
) {
  trees.forEach((tree) => {
    calculate(tree, custChecked, checked, halfChecked, currentNode);
  });
}

/**
 * 是否是叶子节点
 * @param item
 */
function isLeaf(item: Tree): boolean {
  return item && item.children && item.children.length === 0;
}
